#!/usr/bin/perl
#
# usage 
#   topReporter.pl remoteAddr remotePort nodeName [nodeName ...]
# 
# WARNING:
#   nodeName must contain number. e.g.: node1 node2 node3

use Socket;

socket(SOCK, PF_INET, SOCK_DGRAM, 0) || die("can not create socket $!\n");
#setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die("setsockopt() failed. $!\n");

$addr = shift;
$port = shift;

die("inet_aton('$addr') failed. $!\n") unless($inetAddr = inet_aton($addr));
$remote = pack_sockaddr_in($port, $inetAddr);

@nodeNames = @ARGV;
$cpuNum = &GetCPUNum();
foreach $node (@nodeNames){
	if($node =~ m/(\d+)$/){
		$cpuID = $1 % $cpuNum;
		$nodeName2cpuID{$node} = $cpuID;
	}
}
%nodeName2BogoMIPS = &GetBogoMIPS(%nodeName2cpuID);

print("running for @nodeNames\n");
&daemon();

open(TOP, "top -b -d 1 p 1 |")||die("can not read top(1)\n");
while(<TOP>){
	# Cpu0  :  0.0%us,  0.0%sy,100.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
	# Cpu1  :  0.0%us,  0.3%sy, 99.7%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
	# Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
	# Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
	if(m/^Cpu(\d+)/){
		my($cpuID) = $1 + 0;
		m/,\s*([\d\.]+)\%id,\s+/;
		my($noIdlePersent) = 100 - $1;
		my($nodeName);
		foreach $nodeName (keys(%nodeName2cpuID)){
			if($nodeName2cpuID{$nodeName} == $cpuID){
				$nodeName2NoIdle{$nodeName} = $noIdlePersent;
			}
		}
		#print(100 - $1, " -> $_\n");
		if($cpuID == $cpuNum - 1){
			my($buf) = '';
			my(@jsonList);
			foreach $nodeName (keys(%nodeName2NoIdle)){
				push(@jsonList, sprintf('"%s":{"Workload":%f,"BogoMIPS":%f}'
					, $nodeName, $nodeName2NoIdle{$nodeName}
					, $nodeName2BogoMIPS{$nodeName}));
			}
			my($buf) = join(',', @jsonList);
			&SendData($remote, $buf);
		}
	}
}

sub SendData{
	my($remote, $buf) = @_;
	#send(SOCK, $buf, length($buf), $remote);
	send(SOCK, $buf, 0, $remote);
	print(sprintf("%d: %s\n", length($buf), $buf));
}

sub GetCPUNum{
        my($num) = 0;
        if(open(STAT, "</proc/stat")){
                while(<STAT>){
                        $num = $1 if(m/^cpu(\d+)/);
                }
                close(STAT);
        }
        return $num + 1;
}

sub daemon{
        close(STDIN); close(STDOUT); close(STDERR);
        open STDIN, "/dev/null";
        open STDOUT, ">>/dev/null";
        open STDERR, ">>/dev/null";

        if($pid = fork()){
                exit(0);
        }elsif(defined($pid)){
                setsid;
                return 1;
        }else{
                # filed.
                return 0;
        }
        return 0;
}

sub GetBogoMIPS{
	my(%nodeName2cpuID) = @_;
	my(%result);

	return unless(open(CPUINFO, "</proc/cpuinfo"));
	my($cpuID) = -1;
	while(<CPUINFO>){
		# processor       : 1
		# bogomips        : 5319.99
		$cpuID = $1 if(m/^processor\s*:\s*(\d+)/);
		my($nodeName);
		if(m/^bogomips\s*:\s*([\d\.]+)/ && $cpuID >= 0){
			my($bogoMIPS) = $1;
			foreach $nodeName (keys(%nodeName2cpuID)){
				$result{$nodeName} = $bogoMIPS if($cpuID == $nodeName2cpuID{$nodeName});
			}
		}
	}
	close(CPUINFO);
	return %result;
}
